using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Shapes;
using System.Windows.Media;
using System.Windows;
using System.Windows.Controls;

using WozLib.UI.Ink.SketchProperties;
using System.Diagnostics;
using System.Windows.Media.Imaging;
using System.IO;
using WozLib.Net;
using System.Net;
using WozLib.UI.Ink.SketchObjects;

namespace WozLib.UI.Ink.SketchElements
{
  public class SketchEllipse : Canvas, ISketchObject
  {
    public static SketchEllipse FromEllipseWozObject(EllipseSketchObject ellipseWozObject)
    {
      SketchPropertyCollection wozPropertyCollection = new SketchPropertyCollection();
      wozPropertyCollection.WozProperties = ellipseWozObject.WozProperties;

      return new SketchEllipse(ellipseWozObject.WozID, wozPropertyCollection);
    }

    private static Ellipse GetDefaultEllipse(Canvas canvas)
    {
      return GetDefaultEllipse(new Rect(new Point(0.0, 0.0), new Point(1.0, 1.0)), canvas, false);
    }

    private static Ellipse GetDefaultEllipse(Rect rect, Canvas canvas, bool imageFill)
    {

      Ellipse ellipse = new Ellipse();
      ellipse.SetValue(Canvas.LeftProperty, 0.0);
      ellipse.SetValue(Canvas.TopProperty, 0.0);
      ellipse.Width = rect.Width;
      ellipse.Height = rect.Height;
      canvas.Width = rect.Width;
      canvas.Height = rect.Height;
      canvas.SetValue(InkCanvas.LeftProperty, rect.X);
      canvas.SetValue(InkCanvas.TopProperty, rect.Y);
      ellipse.Stroke = Brushes.Black;
      if (imageFill)
      {
        ellipse.StrokeThickness = 0.0;
      }
      else
      {
        ellipse.StrokeThickness = 2.0;
        ellipse.Fill = Brushes.Transparent;
      }
      
      

      canvas.Children.Add(ellipse);
      return ellipse;
    }

    

    public Ellipse Ellipse
    {
      get { return _Ellipse; }
      set { _Ellipse = value; }
    } private Ellipse _Ellipse;

    public SketchEllipse()
      : this(new Rect(new Point(0.0,0.0),new Point(1.0,1.0)),null)
    {
    }

    public SketchEllipse(Rect rect, SketchObjectRegistry wozObjectRegistry) : this (rect,wozObjectRegistry, null)
    {
    }

    public SketchEllipse(Rect rect, SketchObjectRegistry wozObjectRegistry, string imageUrl)
    {



      if (imageUrl != null)
      {
        Ellipse = GetDefaultEllipse(rect, this, true);

        try
        {
          // try to create an image from the url
          BitmapImage bitmapImage = new BitmapImage(new Uri(imageUrl));

          // make the rectangle's fill the image
          Ellipse.Fill = new ImageBrush(bitmapImage);
        }
        catch (Exception ex)
        {
          Debug.WriteLine(ex);
        }
      }
      else
      {
        Ellipse = GetDefaultEllipse(rect, this, false);
      }

      // register this object
      if (wozObjectRegistry != null)
      {
        wozObjectRegistry.RegisterObject(this);
      }
      else
      {
        
      }

      // Set all of our WozPropertyCollection properties

      // Set color property
      if (Ellipse.Stroke is SolidColorBrush)
      {
        ColorSketchProperty colorWozPropertyStroke = new ColorSketchProperty((Ellipse.Stroke as SolidColorBrush).Color, WozPropertyType.StrokeColor);
        this.SetProperty(colorWozPropertyStroke);
      }

      // set the stroke thickness
      ThicknessSketchProperty wozThicknessProperty = new ThicknessSketchProperty(new Thickness(Ellipse.StrokeThickness));
      this.SetProperty(wozThicknessProperty);

      // set whether the stroke is dashed
      BooleanSketchProperty strokeDashed = new BooleanSketchProperty(false, WozPropertyType.StrokeDashed);
      this.SetProperty(strokeDashed);

      if (Ellipse.Fill is SolidColorBrush)
      {
        ColorSketchProperty colorWozPropertyFill = new ColorSketchProperty((Ellipse.Fill as SolidColorBrush).Color, WozPropertyType.FillColor);
        this.SetProperty(colorWozPropertyFill);
      }
      else if (Ellipse.Fill is ImageBrush)
      {
        StringSketchProperty stringWozProperty = new StringSketchProperty(imageUrl,WozPropertyType.FillImageUrl);
        this.SetProperty(stringWozProperty);
      }

      // set the points
      RectGeometrySketchProperty rectGeometryWozProperty = new RectGeometrySketchProperty(rect, WozPropertyType.RectGeometry);
      this.SetProperty(rectGeometryWozProperty);
    }

    public SketchEllipse(long id, SketchPropertyCollection wozPropertyCollection)
      : this(id, wozPropertyCollection, null)
    {
    }

    public SketchEllipse(long id, SketchPropertyCollection wozPropertyCollection, SketchObjectRegistry wozObjectRegistry)
      : base()
    {

      Ellipse = GetDefaultEllipse(this);

      // assign our ID before we doing anything else
      this._WozID = id;

      // overwrite our blank collection with the provided one
      this._WozPropertyCollection = wozPropertyCollection;

      // all of our properties can be set this way
      SetProperty(wozPropertyCollection.WozProperties);

      // register this object
      if (wozObjectRegistry != null)
      {
        wozObjectRegistry.RegisterObjectWithExisitingId(this);
      }
    }

    #region IWozObject Members

    // our private way of holding an ID
    private long _WozID = long.MinValue;

    public long WozID
    {
      get 
      {
        return _WozID;
      }
      set
      {
        _WozID = value;
      }
    }

    // our private way of holding properties
    protected SketchPropertyCollection _WozPropertyCollection = new SketchPropertyCollection();

    // You should update your properties to reflect the actualy state of your underlying object
    // i.e if your current color property says Black, but your stroke actually had its color
    // changed to Red recently - change the color property to red
    public void SyncProperties()
    {
      SyncProperties(_WozPropertyCollection);
    }

    // You should update your properties to reflect the actualy state of your underlying object
    // i.e if your current color property says Black, but your stroke actually had its color
    // changed to Red recently - change the color property to red
    protected void SyncProperties(SketchPropertyCollection wozPropertyCollection)
    {
      RectGeometrySketchProperty rectGeometryWozProperty = new RectGeometrySketchProperty(
        new Rect((double)GetValue(InkCanvas.LeftProperty),(double)GetValue(InkCanvas.TopProperty),this.Width,this.Height),
        WozPropertyType.RectGeometry);
      SetProperty(rectGeometryWozProperty);
    }

    // Set the property, but also make the corresponding change to the underlying object
    // i.e. if the color property is set on a stroke, actually change the drawing attributes
    public void SetProperty(WozLib.UI.Ink.SketchProperties.SketchProperty wozProperty)
    {
      _WozPropertyCollection.SetProperty(wozProperty);

      UpdateProperty(wozProperty);
    }

    private void UpdateProperty(WozLib.UI.Ink.SketchProperties.SketchProperty wozProperty)
    {
      try
      {
        // Figure out what we should with this property
        switch (wozProperty.WozPropertyType)
        {
          case WozPropertyType.StrokeColor:
            Ellipse.Stroke = new SolidColorBrush((wozProperty as ColorSketchProperty).Data);
            break;
          case WozPropertyType.FillColor:
            Ellipse.Fill = new SolidColorBrush((wozProperty as ColorSketchProperty).Data);
            break;
          case WozPropertyType.FillImageUrl:
            try
            {
              // try to create an image from the url
              BitmapImage bitmapImage = new BitmapImage(new Uri((wozProperty as StringSketchProperty).Data));


              // make the rectangle's fill the image
              ImageBrush ib = new ImageBrush(bitmapImage);
              Ellipse.Fill = ib;
              this.InvalidateVisual();
              //Rectangle.InvalidateVisual();
            }
            catch (Exception ex)
            {
              Debug.WriteLine(ex);
            }
            break;
          case WozPropertyType.StrokeDashed:
            // if true
            // StrokeDashArray="2"
            if ((wozProperty as BooleanSketchProperty).Data)
            {
              Ellipse.StrokeDashArray = new DoubleCollection(new double[] { 2.0 });
            }
            else
            {
              Ellipse.StrokeDashArray = null;
            }
            break;
          case WozPropertyType.StrokeThickness:
            Ellipse.StrokeThickness = (wozProperty as ThicknessSketchProperty).Data.Left;
            break;
          case WozPropertyType.RectGeometry:
            Rect rect = (wozProperty as RectGeometrySketchProperty).Rect;

            this.SetValue(InkCanvas.LeftProperty, rect.X);
            this.SetValue(InkCanvas.TopProperty, rect.Y);
            this.Ellipse.Width = rect.Width;
            this.Ellipse.Height = rect.Height;
            this.Width = rect.Width;
            this.Height = rect.Height;
            break;
          case WozPropertyType.Bounds:
            // don't know how right now
            break;

          default:
            // This shouldn't happen
            Debug.WriteLine(this.ToString() + " doesn't know what to do with a " + wozProperty.WozPropertyType.ToString());
            break;
        }
      }
      catch (Exception ex)
      {
        Debug.WriteLine("SketchLine: Property Setting Failed: " + ex.ToString());
      }
    }

    public void SetProperty(IEnumerable<WozLib.UI.Ink.SketchProperties.SketchProperty> wozProperties)
    {
      foreach (SketchProperty wozProperty in wozProperties)
      {
        SetProperty(wozProperty);
      }
    }

    // just return the specified property
    public SketchProperty GetProperty(WozPropertyType wozPropertyType)
    {
      return _WozPropertyCollection.GetProperty(wozPropertyType);
    }

    // WozPropertyCollection makes a copy for us
    public IEnumerable<SketchProperty> GetProperties()
    {
      return _WozPropertyCollection.WozProperties;
    }

    // Make sure we create the WozObject from the appropriate derived class (LineWozObject)
    public SketchObject GetWozObject()
    {
      return new EllipseSketchObject(WozID, GetProperties());
    }

    #endregion

    #region IWozObject Members


    // maybe i should just check to see if this is in our bounds?
    public bool ShouldErase(Point pointRelativeToUie)
    {
      if (this.InputHitTest(pointRelativeToUie) != null)
      {
        return true;
      }
      else
      {
        return false;
      }
    }

    #endregion
  }
}
